package user

import (
	"cross-shard-channel/common"
	"encoding/json"
	"github.com/eywa-protocol/bls-crypto/bls"
	"io/ioutil"
	"net/http"
)

// 定义回复请求的函数
func InitUpdateRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin InitUpdateRespond")

	// 定义基本结构
	var requestObject InitUpdate
	var responseObject InitUpdateResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// get local information about channel
	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	myBalance := ch.MyBalance
	advBalance := ch.AdvBalance
	advChPub := ch.AdvChPub
	ch.Unlock()

	// generate my lock account
	lockPriForMe, lockPubForMe := GenerateKeyWithPub(advChPub)
	responseObject.Cid = requestObject.Cid
	responseObject.LockPub = lockPubForMe
	if requestObject.Value > 0 {
		responseObject.Ack = advBalance > requestObject.Value
	} else {
		responseObject.Ack = myBalance > requestObject.Value
	}

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	if !responseObject.Ack {
		println("InitUpdateRespond Fail")
		return
	}

	ch.Lock()
	ch.AdvLockPubs = append(ch.AdvLockPubs, requestObject.LockPub)
	ch.MyLockPubs = append(ch.MyLockPubs, lockPubForMe)
	ch.MyLockPris = append(ch.MyLockPris, lockPriForMe)
	ch.Unlock()

	//println("InitUpdateRespond success")
	return
}

func UpdateUnlockRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin UpdateUnlockRespond")

	// 定义基本结构
	var requestObject UpdateUnlock
	var responseObject UpdateUnlockResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 获取相关信息
	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	advMainPub := ch.Adv
	myChPub := ch.MyChPub
	myChPri := ch.MyChPri

	myChBalance := ch.MyBalance
	advChBalance := ch.AdvBalance

	createUTXO := ch.CreateUTXO
	notifyUTXOA := ch.NotifyUTXOA
	notifyUTXOB := ch.NotifyUTXOB

	lockTime := ch.LifeTime
	// lock account information
	myLockPri := ch.MyLockPris[ch.Version+1]
	advLockPub := ch.AdvLockPubs[ch.Version+1]
	ch.Unlock()

	// 验证获取到的交易签名是否正确
	mySig := requestObject.TxUnlockB.Sign(myLockPri)
	requestObject.TxUnlockB.Sigs = []bls.Signature{mySig.Aggregate(requestObject.Sig)}
	if !requestObject.TxUnlockB.Verify() {
		println("ERROR　Signature: Update Unlock Fail")
		return
	}

	// 新建一个公私钥对，用于构建对方的锁定账户
	lockPubA := myChPub.Aggregate(advLockPub)

	// 构建对方的commit交易
	commitInputs := []common.UTXO{createUTXO, notifyUTXOA, notifyUTXOB}
	commitOutputA := common.UTXO{
		lockPubA,
		nil,
		advChBalance - requestObject.Value,
	}
	commitOutputB := common.UTXO{
		myChPub,
		nil,
		myChBalance + requestObject.Value,
	}

	commitOutputs := []common.UTXO{commitOutputA, commitOutputB}
	commitTx := common.GenerateTransactionByUTXO(commitInputs, commitOutputs, 0)
	commitOutputA.Tx_id = commitTx.TxId

	// 构建给对方的解锁交易
	unlockInputs := []common.UTXO{commitOutputA}
	unlockOutputUTXO := common.UTXO{
		advMainPub,
		nil,
		commitOutputA.Balance,
	}
	unlockOutputs := []common.UTXO{unlockOutputUTXO}
	unlockTx := common.GenerateTransactionByUTXO(unlockInputs, unlockOutputs, lockTime)
	unlockSigB := unlockTx.Sign(myChPri)

	// 构造回复信息
	responseObject.Cid = requestObject.Cid
	responseObject.Sig = unlockSigB
	responseObject.TxUnlockA = *unlockTx
	responseObject.TxCommitA = *commitTx

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	// 记录本地数据
	ch.Lock()
	ch.TxCommits = append(ch.TxCommits, requestObject.TxCommitB)
	ch.TxUnlocks = append(ch.TxUnlocks, requestObject.TxUnlockB)
	ch.AdvTxCommits = append(ch.AdvTxCommits, *commitTx)
	ch.Unlock()

	//println("UpdateUnlockRespond success")
	return
}

func UpdateCommitRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin UpdateCommitRespond")

	// 定义基本结构
	var requestObject UpdateCommit
	var responseObject UpdateCommitResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// 获取相关信息
	UN.Lock()
	myMainPub := UN.Pub
	myMainPri := UN.Pri
	UN.Unlock()

	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	myChPri := ch.MyChPri
	myNotifyPri := ch.MyNotifyPri

	advCommitTx := ch.AdvTxCommits[len(ch.AdvTxCommits)-1]
	myCommitTx := ch.TxCommits[len(ch.TxCommits)-1]
	chType := ch.Type
	ch.Unlock()

	// 验证对方发送的内容是否有效
	myMainSig := myCommitTx.Sign(myMainPri)
	myChSig := myCommitTx.Sign(myChPri)
	myNotifySig := myCommitTx.Sign(myNotifyPri)

	var sig0 bls.Signature
	var sig1 bls.Signature
	var sig2 bls.Signature

	if chType == 1 {
		sig0 = requestObject.ChSigA.Aggregate(myChSig)       // for channel fund
		sig1 = requestObject.MainSigA.Aggregate(myNotifySig) // for NotifyUTXOA
		sig2 = myMainSig.Aggregate(requestObject.NotifySigA) // for NotifyUTXOB
	} else {
		sig0 = myChSig.Aggregate(requestObject.ChSigA)       // for channel fund
		sig1 = myNotifySig.Aggregate(requestObject.MainSigA) // for NotifyUTXOA
		sig2 = requestObject.NotifySigA.Aggregate(myMainSig) // for NotifyUTXOB
	}
	myCommitTx.Sigs = []bls.Signature{sig0, sig1, sig2}

	if !myCommitTx.Verify() {
		println("update-commit signature error!")
	}

	// 构造给对方的签名
	advMainSig := advCommitTx.Sign(myMainPri)
	advChSig := advCommitTx.Sign(myChPri)
	advNotifySig := advCommitTx.Sign(myNotifyPri)

	// 生成回复
	responseObject.Cid = requestObject.Cid
	responseObject.MainSigB = advMainSig
	responseObject.ChSigB = advChSig
	responseObject.NotifySigB = advNotifySig

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	// 构建给自己的refund transaction
	refundInputs := []common.UTXO{advCommitTx.Output[1]}
	refundOutputs := []common.UTXO{common.UTXO{
		myMainPub,
		nil,
		advCommitTx.Output[1].Balance,
	}}
	myRefundTx := common.GenerateTransactionByUTXO(refundInputs, refundOutputs, 0)
	sigRefund := myRefundTx.Sign(myChPri)
	myRefundTx.Sigs = []bls.Signature{sigRefund}

	// 记录本地数据
	ch.Lock()
	ch.TxRefunds = []common.Transaction{}

	ch.TxCommits[0].Sigs = []bls.Signature{sig0, sig1, sig2}
	ch.TxRefunds = append(ch.TxRefunds, *myRefundTx)
	ch.Unlock()

	//println("UpdateCommitRespond success")
	return
}

func UpdateKeyExchangeRespond(w http.ResponseWriter, r *http.Request) {
	//println("Begin UpdateKeyExchangeRespond")

	// 定义基本结构
	var requestObject UpdateKeyExchange
	var responseObject UpdateKeyExchangeResponse
	var err error

	// 分析请求数据
	body, _ := ioutil.ReadAll(r.Body)
	err = json.Unmarshal(body, &requestObject)
	if err != nil {
		println(err.Error())
		return
	}

	// get local information about channel
	UN.Lock()
	myMainPub := UN.Pub
	UN.Unlock()
	ch := UN.GetChannelFromNode(requestObject.Cid)
	ch.Lock()
	myChPri := ch.MyChPri
	myLockPri := ch.MyLockPris[ch.Version]
	advCommitTx := ch.AdvTxCommits[ch.Version]
	ch.Unlock()

	responseObject.Cid = requestObject.Cid
	responseObject.Pri = myLockPri

	// 尝试构建punish交易
	inputUTXOs := []common.UTXO{common.UTXO{
		Tx_id:     advCommitTx.TxId,
		PublicKey: advCommitTx.Output[0].PublicKey,
		Balance:   advCommitTx.Output[0].Balance,
	}}
	outputUTXOs := []common.UTXO{common.UTXO{
		Tx_id:     nil,
		PublicKey: myMainPub,
		Balance:   advCommitTx.Output[0].Balance,
	}}
	punishTxForAdv := common.GenerateTransactionByUTXO(inputUTXOs, outputUTXOs, 0)
	sig := punishTxForAdv.MultiSign([]bls.PrivateKey{myChPri, requestObject.Pri})
	punishTxForAdv.Sigs = []bls.Signature{sig}

	if !punishTxForAdv.Verify() {
		println("ERROR: Punish construct Fail")
		responseObject.Cid = 0
	} else {
		ch.Lock()
		ch.TxPunishs = append(ch.TxPunishs, *punishTxForAdv)
		ch.Unlock()
	}

	// 发送response
	ret, err := json.Marshal(responseObject)
	if err != nil {
		println("response marshal error\n", err.Error())
		return
	}
	n, err := w.Write(ret)
	if err != nil {
		println(err.Error())
		return
	} else if n != len(ret) {
		println("send to less")
		return
	}

	ch.Lock()
	ch.Version++
	ch.Unlock()

	//println("UpdateKeyExchangeRespond success")
	return
}
